#include "projectHeader.h"


void* joinTimeOutThread(void *t)
{
	//printf("Inside JoinTimeout\n");
	sleep(joinTimeOut);
	//	sleep(100);
	pthread_mutex_lock(&joinTimeOutBoolMutex);
	joinTimeOutBool=true;
	close(joinTimeOutSockFd);
	//printf("Timeout reached.\n");
	pthread_mutex_unlock(&joinTimeOutBoolMutex);
	pthread_exit(NULL);
}



void* nonBeaconJoinConnect(void *t)
{
	//Refer http://www.logix.cz/michal/devel/various/getaddrinfo.c.xp
	
	struct addrinfo hints, *res, *p;
	int errcode;
	int sockfd=0;
	 list<hostPort>::iterator it;
	 hostPort *peerInfo;
	 //printf("Inside nonBeaconJoinConnect.\n");
	for (it=beaconList.begin(); it!=beaconList.end(); it++)
	{
			
			peerInfo=&(*it);
			
			memset (&hints, 0, sizeof (hints));
			hints.ai_family = PF_UNSPEC;
			hints.ai_socktype = SOCK_STREAM;
			//printf("\n*********************************Connected to %s***************************\n",peerInfo->portNum);
			errcode = getaddrinfo (peerInfo->hostName, peerInfo->portNum, &hints, &res);
			if (errcode != 0)
			{
				//perror("noBeaconJoinConnect: error in getAddrinfo");
				//continue;
				exit(1);
			}

			for(p = res; p != NULL; p = p->ai_next) 
			{
				if ((sockfd = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1) 
				{
					continue;
				}
				/*int reuse_addr=1;
				if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
						(void*)(&reuse_addr), sizeof(int)) == -1) {
						 report error 
						perror("Error in setting socket option...");
						exit(1);
						}
				*/
				if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
				{
					close(sockfd);
					continue;
				}
		//		printf("\n*********************************Connected to %s***************************\n",peerInfo->portNum);
				break;
			}
			if (p != NULL) 
			{
				break;
			}
			freeaddrinfo(res);
			
	}
//printf("\n*********************************Connected***************************\n");
joinTimeOutSockFd=sockfd;
//Now send join msg to the beacon node..

//Populate Join Header and Join Data msg and send.


msgHeaderClass joinMsgSendHeader;
joinReqMsgDataClass joinReqSendData;

	joinReqSendData.HostLocation=location;
	joinReqSendData.HostPort=port;
	strncpy(joinReqSendData.Hostname,myHostName,strlen(myHostName));


	unsigned char *buff1;
	char* msg = (char*)"JNRQ";

	//printf("NodeID is %s\n",nodeInstanceId);
	joinMsgSendHeader.messageType=0xFC;
	buff1=GetUOID((char *)nodeInstanceId,msg,buf, sizeof(buf));
	memcpy(joinMsgSendHeader.UOID,buf,20);
	joinMsgSendHeader.ttlInHeader=ttl;
	joinMsgSendHeader.msgDataLength=sizeof(joinReqSendData.HostPort)+strlen(joinReqSendData.Hostname)+sizeof(joinReqSendData.HostLocation);
	


	if (send(sockfd,&joinMsgSendHeader,sizeof(msgHeaderClass), 0) == -1)
	{
		//printf("ERROR: error in sending Hello Header.\n ");
	}
	char joinReqDataSendBuf[512];
	memset(joinReqDataSendBuf,0,512);
	memcpy(joinReqDataSendBuf,&joinReqSendData.HostLocation ,sizeof(joinReqSendData.HostLocation));
	memcpy((joinReqDataSendBuf+sizeof(joinReqSendData.HostLocation)),&joinReqSendData.HostPort ,sizeof(joinReqSendData.HostPort));
	memcpy((joinReqDataSendBuf+sizeof(joinReqSendData.HostLocation)+sizeof(joinReqSendData.HostPort)),&joinReqSendData.Hostname ,strlen(joinReqSendData.Hostname));
	
	if (send(sockfd,joinReqDataSendBuf,joinMsgSendHeader.msgDataLength, 0) == -1)
	{
		//printf("ERROR: error in sending Hello Data.\n\n");
	}
	/*
	pthread_mutex_lock(&printMutex);
	printf("SEND NBJoinConnect:messageType: %u\n",joinMsgSendHeader.messageType);
	printf("SEND NBJoinConnect:");
	printUOID(joinMsgSendHeader.UOID);
	//printUOID(buf);
	printf("SEND NBJoinConnect:ttlInHeader: %u\n",joinMsgSendHeader.ttlInHeader);
	printf("SEND NBJoinConnect:HostLocation: %lu",joinReqSendData.HostLocation);
	printf("SEND NBJoinConnect:HostPort: %d\n",joinReqSendData.HostPort);
	printf("SEND NBJoinConnect:Hostname: %s\n",joinReqSendData.Hostname);
	printf("\n\n");
	pthread_mutex_unlock(&printMutex);

	*/

	pthread_mutex_lock(&logFileMutex);

	gettimeofday(&tv, NULL); 
	int sec = tv.tv_sec ;
	int msec = tv.tv_usec/1000;
	char *time = (char *)malloc(14);
	memset(time,0,14);
	sprintf(time,"%10ld.%03d",(long)sec,msec);
	time[strlen(time)]='\0';
	fprintf(logFilePtr, "s  %s %s:%hu JNRQ %d 0x%02x %x%x%x%x %hu %s\n",time,
		peerInfo->hostName, atoi(peerInfo->portNum),
		(joinMsgSendHeader.msgDataLength+27),
		(unsigned char)joinMsgSendHeader.ttlInHeader,
		(unsigned char)joinMsgSendHeader.UOID[16],
		(unsigned char)joinMsgSendHeader.UOID[17],
		(unsigned char)joinMsgSendHeader.UOID[18],
		(unsigned char)joinMsgSendHeader.UOID[19],
		joinReqSendData.HostPort,joinReqSendData.Hostname);
	pthread_mutex_unlock(&logFileMutex);






















	msgHeaderClass joinMsgRecvHeader;
	unsigned char joinRespRecvBuf[512];

	while(1)
	{
		//printf("CONNECT_NONBEACON JOIN: waiting for join response\n");

		/*get message header from remote socket*/	
		pthread_mutex_lock(&joinTimeOutBoolMutex);
		if(joinTimeOutBool)
		{
			//printf("Timeout thread will break while.\n");
			break;
		}
		pthread_mutex_unlock(&joinTimeOutBoolMutex);


		memset(joinRespRecvBuf,'\0',512);
		memset(&joinMsgRecvHeader,0,sizeof(msgHeaderClass));
		//printf("Before recv1.\n");
		int ret=(int)recv(sockfd,&joinMsgRecvHeader,sizeof(msgHeaderClass),0);
		if(ret==0)
		{
			//close socket;
			continue;
			//break;
		}
		if(ret<0)
		{
			//printf("ERROR: error in recieveing join response in nonBeaconJoinConnect threas.\n");
			break;
			//pthread_exit(NULL);
		}
		
		//ret=0;
		//printf("Before recv2.\n");
		ret=(int)recv(sockfd,joinRespRecvBuf,joinMsgRecvHeader.msgDataLength,0);
		/*if(ret==0)
		{
			//close socket;
			//continue;
			break;
		}*/
		if(ret<0)
		{
			//printf("ERROR: exiting from recv in infinite while.\n");
			break;
			//pthread_exit(NULL);;
		}
		//printf("After recv.\n");		
	

		
	
		joinRespMsgDataClass joinRespRecvData;
		//printf("MessageType Recieved is %x with datalength %d\n",joinMsgRecvHeader.messageType,joinMsgRecvHeader.msgDataLength);
		//printf("Buffer is %s and of length %d\n",joinRespRecvBuf,(int)strlen((const char*)joinRespRecvBuf));
		if(joinMsgRecvHeader.messageType==0xFB)
		{ 
			//printf("Code is here 1!!!\n");

			memcpy(&joinRespRecvData.UOID[0],&joinRespRecvBuf[0],20);
			printUOID(joinRespRecvData.UOID);
			//printf("Code is here 2!!!\n");
			memcpy(&joinRespRecvData.distance,&joinRespRecvBuf[20],4);
			//			printf("NBJOINCONNECT: Recieved join Response with Distance %d from HostName:  and Port: ",joinRespRecvData.distance);
			//printf("Code is here 3!!!\n");
			memcpy(&joinRespRecvData.HostPort,&joinRespRecvBuf[24],2);
			//printf("Code is here 4!!!\n");
			//printf("NBJOINCONNECT: Recieved join Response with Distance %d from HostName:  and Port: %d\n",joinRespRecvData.distance,joinRespRecvData.HostPort);
			memcpy(&joinRespRecvData.Hostname[0],&joinRespRecvBuf[26],joinMsgRecvHeader.msgDataLength-26);
		//	printf("NBJOINCONNECT: Recieved join Response with Distance %d from HostName: %s and Port: %d\n",joinRespRecvData.distance,joinRespRecvData.Hostname,joinRespRecvData.HostPort);
			
			char* hostPortNumberConvert = (char*)malloc(5*sizeof(char));
				sprintf(hostPortNumberConvert,"%d",joinRespRecvData.HostPort);
		//	printf("Convert: %s\n",hostPortNumberConvert);
			//hostPort hostportinfo(joinRespRecvData.Hostname);
			//memcpy(hostportinfo.hostName,joinRespRecvData.Hostname,strlen(joinRespRecvData.Hostname));
			//printf("Code is here 1!!!\n");
			//memcpy(hostportinfo.portNum,hostPortNumberConvert,strlen(hostPortNumberConvert));
			hostPort hostportinfo(joinRespRecvData.Hostname,hostPortNumberConvert);
		//	printf("Code is here 2!!!\n");
			
			multimap<int,hostPort>::iterator it3;
			it3=joinDistList.find(joinRespRecvData.distance);
			if(it3 == joinDistList.end())
			{
				joinDistList.insert( pair<int,hostPort>(joinRespRecvData.distance,hostportinfo) ); 
			}
		//	printf("Code is here 3!!!\n");

		pthread_mutex_lock(&logFileMutex);

gettimeofday(&tv, NULL); 
int sec = tv.tv_sec ;
int msec = tv.tv_usec/1000;
char *time = (char *)malloc(14);
memset(time,0,14);
sprintf(time,"%10ld.%03d",(long)sec,msec);
time[strlen(time)]='\0';
fprintf(logFilePtr, "r  %s %s:%hu JNRS %d 0x%02x %x%x%x%x %x%x%x%x %d %hu %s\n",time,
	joinRespRecvData.Hostname,
	joinRespRecvData.HostPort,
	(joinMsgRecvHeader.msgDataLength+27),
	(unsigned char)joinMsgRecvHeader.ttlInHeader,
	(unsigned char)joinMsgRecvHeader.UOID[16],
	(unsigned char)joinMsgRecvHeader.UOID[17],
	(unsigned char)joinMsgRecvHeader.UOID[18],
	(unsigned char)joinMsgRecvHeader.UOID[19],
	(unsigned char)joinRespRecvData.UOID[16],
	(unsigned char)joinRespRecvData.UOID[17],
	(unsigned char)joinRespRecvData.UOID[18],
	(unsigned char)joinRespRecvData.UOID[19],
	joinRespRecvData.distance,
	joinRespRecvData.HostPort,joinRespRecvData.Hostname);
pthread_mutex_unlock(&logFileMutex);











		}
	
	}
//printf("Going to tested Sleep.\n");
//sleep(30);

pthread_mutex_unlock(&joinTimeOutBoolMutex);


//Write the contents of joinDistList to init_neighbour_list if number of joinResp recieved is >= MinNeighbours.

if((int)joinDistList.size()<initNeighbour)
{
	//printf("NBJoinConnect:Less Number of response than InitNeighbors recieved. Node will shutdown\n ");	
		//put pthread_exit(); and check for size in sv_node.. to decide on exit or restart.
		exit(1);
}
	multimap<int,hostPort>::iterator joinDistListIterator1;
	//printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
	//printf("\nMultimap size : %d\n",joinDistList.size());
	for(joinDistListIterator1=joinDistList.begin();(joinDistListIterator1!=joinDistList.end()) ;joinDistListIterator1++)
	{
			hostPort hp;
			hp=(*joinDistListIterator1).second;
	//		printf("HostName:%s  Port is: %s\n",hp.hostName,hp.portNum);
			//fprintf (initNeighbourListFP, "%s:%s\n",hp.hostName,hp.portNum);

	}


	char initNeighbourListFile[512];
	memset(initNeighbourListFile,'\0',512);
	//printf("HomeDir: %s\n",homeDir);
	memcpy(initNeighbourListFile,homeDir,strlen(homeDir));
	//strcat(initNeighbourListFile,"/files");
	
	//http://www.linuxquestions.org/questions/programming-9/mkdir-in-c-setting-wrong-permissions-613250/
	
	//mkdir(initNeighbourListFile,S_IRWXU | S_IRWXG | S_IRWXO);
	strcat(initNeighbourListFile,"/init_neighbor_list");
	//printf("InitNeighbourList File path is: %s\n",initNeighbourListFile);
	initNeighbourListFP=fopen(initNeighbourListFile,"w");
	if (initNeighbourListFP==NULL)
	{
		//fileOpenSucces=true;	
		// printf("init_neighbor_list.ini not opened succesfully \n");
		pthread_exit(NULL);
		 exit(0);
	}
	
	multimap<int,hostPort>::iterator joinDistListIterator;

	int wrtieCount=0;
	for(joinDistListIterator=joinDistList.begin();(joinDistListIterator!=joinDistList.end())&& (wrtieCount<initNeighbour) ;joinDistListIterator++,wrtieCount++)
	{
			hostPort hp;
			hp=(*joinDistListIterator).second;
		//	printf("HostName:%s  Port is: %s\n",hp.hostName,hp.portNum);
			fprintf (initNeighbourListFP, "%s:%s\n",hp.hostName,hp.portNum);

	}
	fclose(initNeighbourListFP);
pthread_exit(NULL);

}






